package event;

import node.NodeDescriptor;
import event.Event;

import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.Iterator;


/**
 * This class implements EQueue and contains implementation of the real event code
 * @see event.EQueue
 * @author Argo
 *
 */
public class rEQueue implements EQueue{
	 
	private static final int ENQUEUE_UNKNOWN_ERROR 	= -1;
	private static final int ENQUEUE_OK 			= 0;
	private static final int ENQUEUE_MAX_SIZE_ERROR	= 1;
	private BlockingQueue<Event> realQueue = null;
	private BlockingQueue<Event> Queue = null;
	private rEQueueListener queueDelegate;
	
		
	/**
	 * Builder
	 */	
	public rEQueue(){
		super();
		this.realQueue =  new LinkedBlockingQueue<Event>(NodeDescriptor.getInstance().getESize());	
		this.Queue = new LinkedBlockingQueue<Event>(NodeDescriptor.getInstance().getESize());
		this.queueDelegate = null;
	}
	
	/**
	 * Returns the event queue's current size
	 * @return the queue's size
	 */
	public synchronized int getCurrentSize()
    {
    	return this.realQueue.size();
    }
	
	/**
	 * 
	 * @return the real event queue
	 */
	public Queue<Event> getQueue()
	{
	   	return this.realQueue;
	}
	
	    
	/**
	 * Insert the Event 'e' into the event queue 
	 * @param e event will be insert into the queue
	 * @exception InterruptedException
	 * @return 1 if e is successfully inserted into the queue; -1 if occurs an exception
	 */
	@Override
	public synchronized int enqueue(Event e) {
		
		 try 
		 {
			 if(this.Queue.size()<NodeDescriptor.getInstance().getESize()){
		        Queue.put(e);
		        if(Queue.size()==1 && this.queueDelegate!=null)
		        	this.queueDelegate.queueHasGotElements(this, e);
	  	      
		        System.out.println(" >> rEQueue: Event enqueued into local queue.\n >> : " + e);
	  	    	return rEQueue.ENQUEUE_OK;
			 }
			 else
			 {
				 return rEQueue.ENQUEUE_MAX_SIZE_ERROR;
			 }
	     }
	 	 catch (InterruptedException ex) 
	 	 {
	 		 return rEQueue.ENQUEUE_UNKNOWN_ERROR;
	 	 }
	}

	/**
	 * Take a event from the event queue and remove it 
	 * @exception InterruptedException
	 * @return a event
	 */
	@Override
	public synchronized Event dequeue() {

		Event tempEvent = Queue.poll();
		if(Queue.isEmpty() && this.queueDelegate!=null)
			this.queueDelegate.queueHasNoElements(this);
			
        System.out.println(" >> rEQueue: Dequeued from Local Queue:\n >> " + tempEvent);
			
        return tempEvent;
	}
	
	/**
	 * This method make a string inside which is the whole queue of local events
	 * It use the iterator item to scan the queue
	 * @see java.util.Iterator
	 * @return a string containing the contents of the local event queue
	 */
	public String toString()
	{
		String returnString = "LocalEventQueue: ";
		Iterator<Event> it = this.Queue.iterator();
		while(it.hasNext())
		{
			returnString = "\n\t" + it.next() + ",\n";
		}
		return returnString;
	}
	
	public void setQueueDelegate(rEQueueListener delegate){
		this.queueDelegate = delegate;
	}
}
